package cn.sytton.taffe.job.util;

import cn.hutool.core.util.StrUtil;
import cn.sytton.taffe.framework.util.SpringContextUtil;
import cn.sytton.taffe.job.entity.JobEntity;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * 任务执行工具
 *
 * @author ruoyi
 */
public class JobInvokeUtil {
    /**
     * 执行方法
     *
     * @param jobEntity 系统任务
     */
    public static void invokeMethod(JobEntity jobEntity) throws Exception {
        String invokeTarget = jobEntity.getInvokeTarget();
        String beanName = getBeanName(invokeTarget);
        String methodName = getMethodName(invokeTarget);
        List<Object[]> methodParams = getMethodParams(invokeTarget);

        Object bean;
        if (!isValidClassName(beanName)) {
            bean = SpringContextUtil.getBean(beanName);
        } else {
            bean = Class.forName(beanName).newInstance();
        }
        invokeMethod(bean, methodName, methodParams);
    }

    /**
     * 调用任务方法
     *
     * @param bean         目标对象
     * @param methodName   方法名称
     * @param methodParams 方法参数
     */
    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        if (methodParams != null && methodParams.size() > 0) {
            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
            method.invoke(bean, getMethodParamsValue(methodParams));
        } else {
            Method method = bean.getClass().getMethod(methodName);
            method.invoke(bean);
        }
    }

    /**
     * 校验是否为为class包名，
     *
     * @param invokeTarget 名称
     * @return true是 false否
     */
    public static boolean isValidClassName(String invokeTarget) {
        //如果有. 说明是个Class类，例如 cn.sytton.taffe.job.task.TestTask
        //如果没有. 说明是个beanId 例如 testTask
        return StrUtil.contains(invokeTarget, ".");
    }

    /**
     * 获取bean名称
     *
     * @param invokeTarget 目标字符串
     * @return bean名称
     */
    public static String getBeanName(String invokeTarget) {
        return StrUtil.subBefore(invokeTarget, ".", false);
    }

    /**
     * 获取bean方法
     *
     * @param invokeTarget 目标字符串
     * @return method方法
     */
    public static String getMethodName(String invokeTarget) {
        if (invokeTarget.contains("(")) {
            return StrUtil.subBetween(invokeTarget, ".", "(");
        } else {
            return StrUtil.subAfter(invokeTarget, ".", true);
        }
    }

    /**
     * 获取method方法参数相关列表
     *
     * @param invokeTarget 目标字符串
     * @return method方法相关参数列表
     */
    public static List<Object[]> getMethodParams(String invokeTarget) {
        String paramsStr = StrUtil.subBetween(invokeTarget, "(", ")");
        if (!StringUtils.hasText(paramsStr)) {
            return null;
        }
        String[] methodParams = paramsStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
        List<Object[]> cls = new LinkedList<>();
        for (String methodParam : methodParams) {
            String str = StrUtil.trimToEmpty(methodParam);
            if (StrUtil.startWithAny(str, "'", "\"")) {
                // String字符串类型，以'或"开头
                cls.add(new Object[]{StrUtil.sub(str, 1, str.length() - 1), String.class});
            } else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
                // boolean布尔类型，等于true或者false
                cls.add(new Object[]{Boolean.valueOf(str), Boolean.class});
            } else if (StrUtil.endWith(str, "L")) {
                // long长整形，以L结尾
                cls.add(new Object[]{Long.valueOf(StrUtil.sub(str, 0, str.length() - 1)), Long.class});
            } else if (StrUtil.endWith(str, "D")) {
                // double浮点类型，以D结尾
                cls.add(new Object[]{Double.valueOf(StrUtil.sub(str, 0, str.length() - 1)), Double.class});
            } else {
                // 其他类型归类为整形
                cls.add(new Object[]{Integer.valueOf(str), Integer.class});
            }
        }
        return cls;
    }

    /**
     * 获取参数类型
     *
     * @param methodParams 参数相关列表
     * @return 参数类型列表
     */
    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
        Class<?>[] cls = new Class<?>[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            cls[index] = (Class<?>) os[1];
            index++;
        }
        return cls;
    }

    /**
     * 获取参数值
     *
     * @param methodParams 参数相关列表
     * @return 参数值列表
     */
    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
        Object[] cls = new Object[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            cls[index] = os[0];
            index++;
        }
        return cls;
    }
}
